﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Media;
using Galaktika.BI.Charting;
using Galaktika.BI.Charting.PivotChart;
using Galaktika.BI.Extensibility.Dom;
using Galaktika.BI.Runtime.Services;
using Galaktika.BI.Silverlight.Charting;
using Galaktika.BI.Silverlight.Controls.Data;
using Galaktika.BI.Silverlight.Controls.OLAP.Descriptions;
using Galaktika.BI.Silverlight.Intermediate.Charting;
using Visifire.Charts;
using Ranet.Olap.Core.Data;
using Ranet.AgOlap.Controls.ContextMenu;

namespace Galaktika.BI.Silverlight.Controls.Charting
{
    public class ChartingCommon
    {
        public const string DEFAULT_PALETTE_NAME = "Visifire2";
        private Chart m_chart;
        //private RanetChart_v2 m_chart2;

        public ChartingCommon(Chart chart)
        {
            m_chart = chart;
        }


        public void UpdateChartPalettes(string paletteName, IBindingContext context)
        {
            if (this.m_chart.ColorSets.GetColorSetByName(paletteName) != null)
            {
                this.m_chart.ColorSet = paletteName; //initialize with APaletteName
            }
            else
            {
                if (paletteName.Contains("."))
                {
                    var userPalette = new ColorSet();
                    userPalette.Id = paletteName;
                    userPalette.Brushes = this.UpdateChartPalettesFromGlobalSource(context, paletteName);
                    this.m_chart.ColorSets.Add(userPalette);
                    this.m_chart.ColorSet = userPalette.Id;
                }
                else
                    this.m_chart.ColorSet = ChartingCommon.DEFAULT_PALETTE_NAME;
            }
        }

        private Collection<Brush> UpdateChartPalettesFromGlobalSource(IBindingContext context, string paletteName)
        {

            var app = context.Services.GetService(typeof(IAppManager)) as IAppManager;
            BrickPalette globalPalette = PaletteHelper.GetPalette(paletteName, app);
            if (globalPalette != null)
                return this.AddGlobalPaletteToChartRepository(globalPalette);
            return null;
        }

        private Collection<Brush> AddGlobalPaletteToChartRepository(BrickPalette userPaletteEntry)
        {
            string paletteName = userPaletteEntry.Name;
            var brushes = new Collection<Brush>();
            foreach (var userPaletteItem in userPaletteEntry.Items)
            {
                if (userPaletteItem.Color2 != null)
                {
                    var coll = new GradientStopCollection();
                    coll.Add(new GradientStop()
                    {
                        Color = userPaletteItem.Color1
                    });
                    coll.Add(new GradientStop()
                    {
                        Color = userPaletteItem.Color2,
                        Offset = 2
                    });
                    var paletteEntry = new LinearGradientBrush(coll, 45);
                    brushes.Add(paletteEntry);
                }
                else
                {
                    brushes.Add(new SolidColorBrush(userPaletteItem.Color1));
                }
            }
            return brushes;
        }

        public DataSeries[] CreateBubbleSeries(object aDataSource, string formatString)
        {
            var seriesList = new List<DataSeries> { };

            if (aDataSource is DataTableWrapper)
            {

#warning работает только с 1 Series

                var data = aDataSource as DataTableWrapper;
                //в Win версии не релизовано, поэтому поведение на Silverlight не понятно.

                RelationalData[] bindCollection = new RelationalData[data.RowCount];
                DataPointCollection dataCollection = new DataPointCollection();
                int i = 0;
                int j = 0;
                for (j = 0; j < data.RowCount; j++)
                {
                    var bindObject =
                        new RelationalData() { First = data.Items[i], Second = Convert.ToInt32(data.Items[i + 1]) };
                    dataCollection.Add(new DataPoint() { YValue = bindObject.Second, XValue = bindObject.First });
                    i += 2;
                    bindCollection[j] = bindObject;
                }
                var s = new DataSeries();
                foreach (var d in dataCollection)
                    s.DataPoints.Add(d);
                seriesList.Add(s);
            }
            if (aDataSource is CellSetData)
            {
                var data = aDataSource as CellSetData;
                int i = 0;
                int j = 0;

                var series = new DataSeries();
                var dataSource = new FlatDescriptionCollection();
                foreach (var rows in data.Axes[1].Positions)
                {
                    if (data.GetCellDescription(i, j).Value != null)
                    {
                        try
                        {
                            if (data.GetCellDescription(i, j).Value.Value == null)
                            {
                                j++;
                                continue;
                            }
                            string m_YValueFormat;

                            var obj = new FlatDescription();
                            var point = new DataPoint();
                            point.Parent = series;

                            double value;
                            if (ValueHelper.TryConvert(data.GetCellDescription(i, j).Value.Value, out value))
                                point.XValue = value;
                            else
                                point.AxisXLabel = data.GetCellDescription(i, j).Value.Value.ToString();

                            point.LabelText = GetFormattedValue(formatString, out m_YValueFormat);
                            point.Parent.YValueFormatString = m_YValueFormat;
                            //point.LabelText = value.ToString("### ##0.##");
                            obj.DisplayValue = value;

                            point.YValue = ValueHelper.ToDouble(data.GetCellDescription(i + 1, j).Value.Value);
                            obj.ArgumentSegments.Add(point.YValue);
                            point.ZValue = ValueHelper.ToDouble(data.GetCellDescription(i + 2, j).Value.Value);
                            obj.ZValue = point.ZValue;
                            if (!String.IsNullOrEmpty(point.AxisXLabel))
                                point.Name = point.AxisXLabel + i.ToString();
                            var seriesMembers = from y in rows.Members
                                                select y.Caption;
                            point.LegendText = string.Join(".", seriesMembers.ToArray());
                            point.ToolTipText = String.Format("{0}\\n#XValue\\n#YValue\\n#ZValue", point.LegendText);
                            point.ShowInLegend = true;


                            series.DataPoints.Add(point);
                            foreach (var members in rows.Members)
                            {
                                obj.UniqueNameSegments.Add(members.Caption);
                            }
                            dataSource.Add(obj);
                            j++;
                        }
                        catch
                        {
                            continue;
                        }
                    }
                }
                series.Tag = dataSource;
                series.LabelEnabled = true;
                series.SelectionEnabled = true;
                seriesList.Add(series);               
            }
            return seriesList.ToArray();
        }


        public List<DataSeries> ProcessPivotTable(object aDataSource, object diagramType,string formatString, bool legendVisible)
        {

            //object chartSeries = null;
            var seriesList = new List<DataSeries> { };
            bool isDateTime = false;

            if (aDataSource is DataTableWrapper)
            {

#warning работает только с 1 Series

                var data = aDataSource as DataTableWrapper;
                //в Win версии не релизовано, поэтому поведение на Silverlight не понятно.

                var bindCollection = new RelationalData[data.RowCount];
                var dataCollection = new DataPointCollection();
                int i = 0;
                int j = 0;
                for (j = 0; j < data.RowCount; j++)
                {
                    var bindObject =
                        new RelationalData() { First = data.Items[i], Second = Convert.ToInt32(data.Items[i + 1]) };
                    dataCollection.Add(new DataPoint() { YValue = bindObject.Second, XValue = bindObject.First });
                    i += 2;
                    bindCollection[j] = bindObject;
                }
                var s = new DataSeries();
                foreach (var d in dataCollection)
                    s.DataPoints.Add(d);
                seriesList.Add(s);
            }

            if (aDataSource is CellSetData)
            {
                var data = aDataSource as CellSetData;
                int i = 0;
                foreach (var rows in data.Axes[0].Positions)
                {
                    int j = 0;
                    var series = new DataSeries();
                    var dataSource = new FlatDescriptionCollection();
                    string m_YFormatValue = string.Empty;

                    foreach (var columns in data.Axes[1].Positions)
                    {
                        var obj = new FlatDescription();
                        var point = new DataPoint();
                        point.Parent = series;
                        foreach (var members in columns.Members)
                        {
                            if (!String.IsNullOrEmpty(members.Caption))
                            {
                                DateTime arg;
                                obj.ArgumentSegments.Add(members.Caption);
                                point.AxisXLabel = members.Caption;
                                //point.ShowInLegend = false;
                                try
                                {
                                    DateTime date;
                                    obj.UniqueNameSegments.Add(members.UniqueName);
                                    if (data.GetCellDescription(i, j).Value != null)
                                    {
                                        if (ValueHelper.TryConvert(
                                            data.GetCellDescription(i, j).Value.Value, out date))
                                        {
                                            obj.DisplayValue = date.ToShortDateString();
                                        }
                                        else
                                        {
                                            double value =
                                                Convert.ToDouble(data.GetCellDescription(i, j).Value.Value);
                                            point.YValue = value;
                                            obj.DisplayValue = value;
                                            point.LabelText = GetFormattedValue(formatString, out m_YFormatValue);
                                            point.Parent.YValueFormatString = m_YFormatValue;
                                            point.LabelEnabled = legendVisible;
                                            if (diagramType is ViewType)
                                            if (((ViewType)diagramType) == ViewType.Pie ||
                                                ((ViewType)diagramType)== ViewType.Doughnut)
                                            {
                                                if (data.GetCellDescription(i, j).Value.Value == null)
                                                {
                                                    continue;
                                                }
                                                point.LabelText = value.ToString("### ### ### ##0.##");
                                            }
                                            if (value == 0)
                                                point.LabelEnabled = false;

                                        }
                                    }
                                }
                                catch
                                {
                                    continue;
                                }
                            }
                        }
                        point.Name = point.AxisXLabel + i.ToString();
                        series.DataPoints.Add(point);
                        dataSource.Add(obj);
                        j++;
                    }
                    i++;

                    series.Tag = dataSource;
                    var seriesMembers = from y in rows.Members
                                        select y.Caption;
                    series.SelectionEnabled = true;
                    string tip1 = string.Join(".", seriesMembers.ToArray());
                    series.Name = tip1;
                    series.ToolTipText = String.Format("{0}\\n#AxisXLabel\\n#YValue", tip1);
                    //if (diagramType == ViewType.Pie || diagramType == ViewType.Doughnut)
                    //{
                    //    if (string.IsNullOrEmpty(this.ACaption))
                    //        this.ACaption = tip1;
                    //}
                    //else
                    if (diagramType is ViewType)
                    if ((ViewType)diagramType != ViewType.Pie && (ViewType)diagramType != ViewType.Doughnut)
                        series.LegendText = string.Join(".", seriesMembers.ToArray());
                    series.ShowInLegend = legendVisible;
                    seriesList.Add(series);
                }

            }            
            if (seriesList.Count == 1)
            {
                var dummy = new DataSeries();
                var d = new DataPoint();
                dummy.DataPoints.Add(d);
                dummy.LegendText = string.Empty;
                dummy.ShowInLegend = false;
                seriesList.Add(dummy);
            }
           return seriesList;
           //В случае использования Зум-скроллов производим их настройку           
        }

        public DataSeries[] GetSeriesFromDataSourceFlat(object aDataSource, object diagramType, string formatString, bool legendVisible)
        {
            var seriesList = new List<DataSeries> { };

            if (aDataSource is DataTableWrapper)
            {

#warning работает только с 1 Series

                var data = aDataSource as DataTableWrapper;
                //в Win версии не релизовано, поэтому поведение на Silverlight не понятно.

                var bindCollection = new RelationalData[data.RowCount];
                var dataCollection = new DataPointCollection();
                int i = 0;
                int j = 0;
                for (j = 0; j < data.RowCount; j++)
                {
                    var bindObject =
                        new RelationalData() {First = data.Items[i], Second = Convert.ToInt32(data.Items[i + 1])};
                    i += 2;
                    dataCollection.Add(new DataPoint() {XValue = bindObject.First, YValue = bindObject.Second});
                    bindCollection[j] = bindObject;
                }
                var s = new DataSeries();
                s = new DataSeries();
                foreach (var d in dataCollection)
                    s.DataPoints.Add(d);
                seriesList.Add(s);
            }
            if (aDataSource is CellSetData)
            {
                var data = aDataSource as CellSetData;
                int i = 0;                
                    foreach (var rows in data.Axes[0].Positions)
                    {
                        int j = 0;
                        var dataSource = new FlatDescriptionCollection();
                        var series = new DataSeries();
                        double counter = 0;
                        string m_YFormatValue = string.Empty;
                        foreach (var columns in data.Axes[1].Positions)
                        {
                            var obj = new FlatDescription();
                            var point = new DataPoint();
                            point.Parent = series;
                            foreach (var members in columns.Members)
                            {
                                if (!String.IsNullOrEmpty(members.Caption))
                                {
                                    obj.ArgumentSegments.Add(members.Caption);
                                    point.AxisXLabel = members.Caption;
                                    counter += 20;
                                    point.XValue = counter;
                                    try
                                    {
                                        DateTime date;
                                        obj.UniqueNameSegments.Add(members.UniqueName);
                                        if (data.GetCellDescription(i, j).Value != null)
                                        {
                                            if (ValueHelper.TryConvert(
                                                data.GetCellDescription(i, j).Value.Value, out date))
                                            {
                                                obj.DisplayValue = date.ToShortDateString();
                                            }
                                            else
                                            {
                                                if (data.GetCellDescription(i, j).Value.Value == null)
                                                    continue;
                                                double value =
                                                    Convert.ToDouble(data.GetCellDescription(i, j).Value.Value);
                                                point.YValue = value;
                                                series.LabelEnabled = legendVisible;
                                                point.LabelText = GetFormattedValue(formatString,
                                                                                    out m_YFormatValue);
                                                point.Parent.YValueFormatString = m_YFormatValue;
                                                if (value == 0)
                                                    point.LabelEnabled = false;
                                                obj.DisplayValue = value;
                                            }
                                        }
                                    }
                                    catch
                                    {
                                        continue;
                                    }
                                }
                            }
                            point.Name = point.AxisXLabel + i.ToString();
                            series.DataPoints.Add(point);
                            dataSource.Add(obj);
                            j++;
                        }
                        i++;

                        series.Tag = dataSource;
                        var seriesMembers = from y in rows.Members
                                            select y.Caption;
                        string tip1 = string.Join(".", seriesMembers.ToArray());
                        series.Name = tip1;
                        series.ToolTipText = String.Format("{0}\\n#AxisXLabel\\n#YValue", tip1);
                        series.SelectionEnabled = true;
                        seriesList.Add(series);
                    }               

            }
            return seriesList.ToArray();
        }


        private string GetFormattedValue(string formatString, out string m_YValueFormat)
        {
            string resultValue = string.Empty;
            m_YValueFormat = string.Empty;

            string service = string.Empty;
            bool isService = false;
            foreach (var str in formatString.ToCharArray())
            {
                if (str == '{')
                {
                    isService = true;
                    service = string.Empty;
                }
                else if (str == '}')
                {
                    isService = false;
                    if (service.ToLower().Contains("value"))
                        service = service.Replace("value", "#YValue");
                    if (service.ToLower().Contains("label"))
                        service = service.Replace("label", "#AxisXLabel");
                    if (service.ToLower().Contains("percent"))
                        service = service.Replace("percent", "#Percentage");
                    var strings = service.Split(new string[] { "|" }, StringSplitOptions.None);
                    if (strings.Count() > 1 && strings[1].Contains(","))
                        m_YValueFormat = "###,###,###,##0";
                    else
                        m_YValueFormat = "### ### ### ##0";

                    double index = 0;
                    if (strings.Count() > 1 && ValueHelper.TryConvert(strings[1][0].ToString(), out index))
                    {
                        if (index > 0)
                        {
                            m_YValueFormat += ".";
                            while (index > 0)
                            {
                                index--;
                                m_YValueFormat += "#";
                            }
                        }
                    }

                    resultValue += strings[0];
                    service = string.Empty;
                }
                else
                {
                    service += str;
                    if (!isService)
                        resultValue += str;
                }

            }
            return resultValue;
        }

        public void ParseArgsOnMenuItems(CustomContextMenu menu)
        {
            var dp = menu.Tag as DataPoint;
            if (dp != null)
            {
                var parsableArgs = new Dictionary<string, string>();
                foreach (var arg in this.GetContextArgs(dp, dp.Parent))
                {
                    parsableArgs.Add("{{" + arg.Key + "}}", arg.Value);
                }

                foreach (var element in menu.Items)
                {
                    var item = element as ContextMenuItem;
                    if (item == null) continue;
                    var info = item.Tag as ActionInfo;
                    if (info == null) continue;

                    string caption = info.ACaption;
                    foreach (var pArg in parsableArgs)
                    {
                        if (caption.Contains(pArg.Key))
                        {
                            caption = caption.Replace(pArg.Key, pArg.Value);
                        }
                    }
                    item.Caption = caption;
                }
            }
        }
        
        public IDictionary<string, string> GetContextArgs(DataPoint mi, DataSeries series)
        {
            var args = new Dictionary<string, string>();
            if (mi != null)
            {
                if ((mi.Parent.Tag as FlatDescriptionCollection) != null)
                {
                    var dataSource = mi.Parent.Tag as FlatDescriptionCollection;
                    //тут найти новмер значения mi.PointIndex
                    for (int i = 0; i < dataSource[series.DataPoints.IndexOf(mi)].ArgumentSegments.Count; i++)
                    {
                        args.Add(String.Format("UNIQUE_NAME{0}", i), dataSource[series.DataPoints.IndexOf(mi)].UniqueNameSegments.ToArray()[i]);
                        args.Add(String.Format("CAPTION{0}", i), dataSource[series.DataPoints.IndexOf(mi)].ArgumentSegments[i].ToString());
                    }
                    args.Add("seriesName", series.Name); // имя серии на которой был произведен клик
                    args.Add("label", dataSource[series.DataPoints.IndexOf(mi)].Argument.ToString()); // подпись по оси X (аргумент)
                    args.Add("value", dataSource[series.DataPoints.IndexOf(mi)].DisplayValue.ToString()); // значение

                }
            }

            return args;
        }

    }
}
